home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / mush6.4 / part11 < prev    next >
Encoding:
Internet Message Format  |  1989-03-12  |  53.5 KB

  1. Subject:  v18i033:  Mail user's shell version 6.4, Part11/19
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Dan Heller <island!argv@sun.com>
  7. Posting-number: Volume 18, Issue 33
  8. Archive-name: mush6.4/part11
  9.  
  10.  
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line, then unpack
  14. # it by saving it into a file and typing "sh file".  To overwrite existing
  15. # files, type "sh file -c".  You can also feed this as standard input via
  16. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  17. # will see the following message at the end:
  18. #        "End of archive 11 (of 19)."
  19. # Contents:  cmd_help msgs.c
  20. # Wrapped by rsalz@papaya.bbn.com on Mon Mar 13 19:25:17 1989
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'cmd_help' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'cmd_help'\"
  24. else
  25. echo shar: Extracting \"'cmd_help'\" \(27197 characters\)
  26. sed "s/^X//" >'cmd_help' <<'END_OF_FILE'
  27. X/* @(#)cmd_help    1.4    10/24/88 (Dan heller) */
  28. X
  29. X%?%
  30. XThe `?' command will give you a list of legal commands.  Most
  31. Xcommands accept -? as an option.  This will give you specialized
  32. Xhelp with that particular command.
  33. X%%
  34. X
  35. X%ignore%
  36. X      ignore/unignore [headers]
  37. X
  38. XUse this command to set the message headers you would like not
  39. Xto be printed when you read a message. If no header specified,
  40. Xthen a list of all headers currently being ignored is printed.
  41. XYou must specify a header for unignore.
  42. X
  43. XYou can set the variable "alwaysignore" to force normally
  44. Xignored headers to be ignored while saving messages, forwarding
  45. Xmessages or including messages into message buffers.
  46. X%%
  47. X
  48. X%set%
  49. X      set/unset [variable [= value]]
  50. X
  51. XWith no parameters, set lists all variables and their values.
  52. XTo set a boolean variable (on or off), use:
  53. X    set variable
  54. XTo set a variable's value to a string, use:
  55. X    set variable = value
  56. X
  57. XIf you want double-quotes or white-space embedded in a string,
  58. Xencase the string in single quotes.  If you want single quotes
  59. Xin a string, encase the string in double quotes.
  60. X
  61. XFor a list of all variables with special meanings, use:
  62. X    set ?all
  63. XFor help on a particular one of these variables, use:
  64. X    set ?variable_name
  65. X%%
  66. X
  67. X%readmsg%
  68. XYou can read messages in different ways.  "type" and "print"
  69. Xwill print the current message.  "top" will only print the first
  70. XN lines of the current message where N is the value of the
  71. Xvariable "crt".  "next" will go to the next unread message and
  72. Xprint that.  "previous" will go back and read the first unread
  73. Xmessage previous to the current.  "^" will print the first
  74. Xmessage, "$" will print the last.
  75. X
  76. XAny of these commands can be followed by a message list, and
  77. Xeach message in that list will be printed (or piped to other
  78. Xcommands).
  79. X%%
  80. X
  81. X%alts%
  82. X      alts [hostnames]
  83. X
  84. XThe alts command sets a list of hostnames on which you have an
  85. Xaccount.  Normally, when you respond to all recipients of mail,
  86. Xyour account name will be listed as if you wished to send
  87. Xyourself mail.  If you don't have metoo set, then your name will
  88. Xbe removed from the mailing list if your login name is on the
  89. Xlist and the host specified is in the alternates list.  The
  90. Xspecial parameter `*' instructs alts to match all hostnames; in
  91. Xthat case, only the login name is tested.
  92. X%%
  93. X
  94. X%source%
  95. X      source/saveopts [file]
  96. X
  97. XThe source/saveopts commands will load/save all variable
  98. Xsettings, options, aliases, cmd's, ignored headers ...
  99. Xeverything you can set, it loads or saves.  The file read or
  100. Xwritten follows these rules:
  101. X
  102. X1) If a filename is given, that file is used
  103. X2) The file described by the environment variable MAILRC
  104. X3) In the user's home directory: .mushrc (if it exists)
  105. X4) In the user's home directory: .mailrc (if it exists)
  106. X
  107. XIf saveopts is used and the file exists, confirmation will be
  108. Xrequested before the file is overwritten.
  109. X%%
  110. X
  111. X%general%
  112. XThis is the general help message.  To get help on a specific
  113. Xcommand, try "command -?".  Extended help is given by typing
  114. X"help item" where item is one of:
  115. X    path, msg_list, prompt, hdr_format
  116. XHelp with msg_list is highly advisable!
  117. X
  118. XType "?" to get a list of available commands.  Try "? command"
  119. Xto get help on the particular command that you specify.
  120. X%%
  121. X
  122. X%path%
  123. XWhenever "path" is specified, the following syntax is legal
  124. Xbesides the normal path addressing scheme used by unix:
  125. X ~[user]   -- the home directory of specified user (yours by default)
  126. X %[user]   --/usr/spool/mail/login_name [user_name] (yours by default)
  127. X +file     --the directory described by `set folder'; file is `file'
  128. X%%
  129. X
  130. X%msg_list%
  131. XA "msg_list" references one or more messages.  The user
  132. Xspecifies a group of messages according to a special syntax.
  133. X
  134. X *      All messages.
  135. X ^      The first message.
  136. X $      The last message.
  137. X .      The current message.
  138. X N-M    A range of messages between N and M, inclusive.
  139. X
  140. XIn the last case, N and M may be * ^ $ . or digits referencing
  141. Xexplicit message numbers.  The range must be in ascending order.
  142. X
  143. XYou can also negate messages by placing the message list inside
  144. Xbraces, `{' `}' -- thus, the expression "2-19 {11-14}"
  145. Xreferences messages 2 through 19 except for those from 11
  146. Xthrough 14.
  147. X
  148. XCommands can be "piped" to one another, because the return value
  149. Xof a command is a msg_list, not text.  For example,
  150. X    pick -f fred | lpr
  151. Xwill find all messages "from fred" and send them to the printer.
  152. X
  153. XCommands dealing with more than one message process them in
  154. Xnumeric order -- not necessarily the order specified.  Thus, the
  155. Xcommand "save 1-5 9 7 6 file" will save the messages in
  156. Xascending order, not in the order given.
  157. X%%
  158. X
  159. X%preserve%
  160. X      preserve [msg_list]
  161. X
  162. XThe "preserve" command saves deleted or read messages in your
  163. Xmailbox.  Without explicitely setting preserve, all mail that
  164. Xyou read will be saved in ~/mbox (or set mbox).  Setting the
  165. Xboolean variable "hold" is equivalent to preserving each message
  166. Xas you read it.
  167. X%%
  168. X
  169. X%save%
  170. X      save/write/copy [-s|-S|-a|-A] [!] [msg_list] [filename]
  171. X
  172. XIf no filename is specified, ~/mbox (or the value of the
  173. Xvariable "mbox") is used.  Save and write will append msg if
  174. X`file' already exists.  Specifying the `!' will overwrite the
  175. Xfile (e.g., erasing it first).
  176. X
  177. XTo save messages to a filename beginning with a digit, escape
  178. Xthe filename with a backslash (\).
  179. X
  180. XThe "write" command will write message without the headers (msg
  181. Xbody only).  Save and write both mark messages for deletion
  182. Xunless "keepsave" is set.  The "copy" command is identical to
  183. X"save" except that messages are not marked for deletion
  184. X(identical to having the variable "keepsave" set).
  185. X
  186. XThe -s and -S options save messages to files named by the
  187. Xsubject of the message.  If more than one message is specified,
  188. Xthen the message subject of each message is used.  If -S is
  189. Xspecified, then the subject of the first message is used for all
  190. Xmessages.  Spaces and forward slashes (/) are converted to
  191. Xunderscores (_).
  192. X
  193. XThe -a and -A options save messages by author's login name.
  194. X%%
  195. X
  196. X%lpr%
  197. X      lpr [-n] [-h] [msg_list]
  198. X  -n      print body of message only (not headers)
  199. X  -h      print all headers with message body (default true)
  200. X  -Pxx    print on printer xx
  201. X%%
  202. X
  203. X%respond%
  204. X      replysender/replyall [msg_list] [-r path] [mail_flags] [users]
  205. X
  206. XThe "replysender" command replies only to the sender of a
  207. Xmessage, whereas "replyall" responds to everyone on the To: and
  208. XCc: lines of the message.
  209. X
  210. XThe commands "reply" is identical to "replysender".
  211. X
  212. XIf a message list is indicated, then each message on the list is
  213. Xreplied to in the same manner.  If -r is specified with a host or
  214. Xpath (uucp-style), then each address in the list is routed via
  215. Xthis path.  This overrides the value of auto_route (see man page).
  216. X
  217. XThe address of the author is obtained from certain headers in
  218. Xhis message to you.  Unless you specify otherwise, mush will
  219. Xsearch for the headers Reply-To: Return-Path: and From:.  You
  220. Xcan override these values by setting the variable reply_to_hdr.
  221. X
  222. X    set reply_to_hdr = "sender reply-to return-path from_"
  223. X
  224. XThis example shows that mush will search for (in order), the
  225. Xheaders listed in the reply_to_hdr variable.  If one header isn't
  226. Xfound, then mush looks for the next in the list.  If none of the
  227. Xheaders in the list are found, the default headers (mentioned
  228. Xabove) are searched.  The last header listed in the example is
  229. Xthe special "From " header.  See the man page for more details.
  230. X
  231. XType "mail -?" for information on legal mail flags.
  232. X%%
  233. X
  234. X%sort%
  235. X      sort [-] [a|d|R|s|S]
  236. X  a         by author (alphabetical)
  237. X  d         according to date
  238. X  R         by subject including Re: (alphabetical)
  239. X  s         by subject ignoring Re: (alphabetical)
  240. X  S         by status
  241. X
  242. XThe optional `-' flag will reverse the order of sorting.  By
  243. Xdefault (no parameters), sort sorts messages by status:  New,
  244. Xunread messages are first, followed by preserved messages and
  245. Xfinally the deleted messages are placed at the end.
  246. X
  247. XIf the "date_received" variable is set, sorting by date is
  248. Xdone using the date you received the message.  Otherwise,
  249. Xmessages are sorted by date sent by the original author.
  250. X%%
  251. X
  252. X%pick%
  253. X      pick [-x] [-f|s|t] [-h hdr] [-i] [-r msg_list] [<pat>]
  254. X            [-d [-][date]] [-ago [n days] [n weeks] [n months]]
  255. X
  256. XSearch for patterns within messages.  Entire messages are
  257. Xsearched for <pattern> unless -f, -h, -s, or -t is specified.
  258. XOnly one of -d, -f, -h, -s, -t and -ago can be specified; no
  259. Xpattern is used with -d and -ago.
  260. X
  261. X  -x            return those messages which do NOT match
  262. X  -f            match pattern in the "From:" field (author) only
  263. X  -s            match pattern in the "Subject:" header only
  264. X  -t            match pattern in the "To:" field only
  265. X  -h hdr        match pattern in specified header field only
  266. X  -i            ignore case of letters in when matching
  267. X  -r msg_list   restrict the range of messages search to msg_list
  268. X  -d            select messages sent on [+ after] [- before] date
  269. X        A "date" is of the form:  [+-][month]/[date[/year]]
  270. X        Omitted fields default to today's values.  Examples:
  271. X          pick -d 4/20     messages on Apr 20, this year
  272. X          pick -d -/2/85   on or before the 2nd, this month, 1985
  273. X          pick -d +5/4     on or after May 4, this year
  274. X          pick -d /        finds today's messages only
  275. X        At least one `/' char must be used in a date.  There is
  276. X    no strong date checking; 2/30 would be considered valid.
  277. X  -ago          select messages relative to the current date
  278. X    Date formats for "ago" are more verbose than for -d; see
  279. X    the manual page for details.
  280. X%%
  281. X
  282. X%alias%
  283. XOptions for alias:
  284. X alias                       print all namelists
  285. X alias name                  print namelist associated with name
  286. X alias name namelist         set "name" to the value of namelist
  287. X unalias namelist            unalias names in namelist
  288. X
  289. XA "namelist" consists of one or more addresses.  An address may
  290. Xbe a name already set to another list, a valid user, a file or
  291. Xa program.  Filenames must be full pathnames, i.e., they must
  292. Xbegin with a '/' (or with a ~, which expands to some home dir).
  293. XA "program" must start with a pipe symbol and be encased in
  294. Xquotes:
  295. X
  296. X    "|program_name"
  297. X
  298. XThe command "expand" will print addresses (including sublists)
  299. Xassociated with the given alias.
  300. X%%
  301. X
  302. X%from%
  303. XWith no parameters, "from" will print the current message's
  304. Xheader line.  If given a message list, "from" will print the
  305. Xheaders of the listed messages.
  306. X
  307. XThe special parameters `-' and `+' can be given to move the
  308. Xcurrent message pointer to the previous or next message
  309. Xrespectively, while also printing that message's header.
  310. X
  311. XIf a message list was given in addition to `-' or `+', then
  312. Xthe current message pointer will be set to the first or last
  313. Xmessage, respectively, in the message list given.
  314. X
  315. XExamples:
  316. X
  317. X    from - 10-30 {16}
  318. Xwill print the headers of messages 10 through 30 except for
  319. Xmessage 16 and set the current message pointer to 10.
  320. X
  321. X    pick -f Dan | from +
  322. Xwill print the headers of all messages that contain "Dan" in the
  323. Xauthor's name and set the current message pointer to the last
  324. Xone of that kind in the list.
  325. X
  326. X    from +
  327. Xwill print the header of the message after the current message
  328. Xand increment the current message pointer to that message.
  329. X%%
  330. X
  331. X%own_hdrs%
  332. XThis command is used to set, unset or view your personalized
  333. Xmessage headers.  These headers are included in all your
  334. Xoutgoing mail.
  335. X
  336. XOptions for my_hdr:
  337. X  my_hdr            show all headers
  338. X  my_hdr header            show value of header
  339. X  my_hdr header: string        set header to string
  340. X  un_hdr header            unset header
  341. X%%
  342. X
  343. X%fkey%
  344. XThis command is used to make function key settings in Suntools
  345. X(graphics) mode.  When run as a tool (-t on command line),
  346. Xchoose the Options item, and the "function key" menu option.
  347. X%%
  348. X
  349. X%cmd%
  350. XThis function is used to establish command aliases; cmd's are
  351. Xjust like aliases in the C-shell.  Options are:
  352. X  cmd                       view all commands
  353. X  cmd command               show value of command
  354. X  cmd command "value"       set command to value
  355. X  uncmd command             unset command
  356. X
  357. XIf you want to reference history commands within a cmd,
  358. Xescape the ! with a backslash.  For example:
  359. X
  360. X    cmd r 'replysender \!* ; delete -t'
  361. X
  362. Xwill cmd "r" to reply using whatever parameters you have given on
  363. Xthe command line and then delete that message and print the next
  364. Xmessage (-t parameter to "delete").
  365. X%%
  366. X
  367. X%headers%
  368. X      headers [+|-|N] [[-H]:c]
  369. X  +    print the next screenful (or use the 'z' command).
  370. X  -    print the previous screenful (or use 'z-' ).
  371. X  N    print a screenful starting at message number N.
  372. X  -H:c  where `c' is one of
  373. X     a  all messages (mostly for the command line parameter -H:c)
  374. X     d  deleted messages
  375. X     n  new messages
  376. X     o  old messages
  377. X     p  preserved messages
  378. X     r  replied-to messages
  379. X     s  saved messages
  380. X     u  unread messages
  381. X
  382. XThe "headers" command prints out a screenful of headers.
  383. XDeleted messages are not normally shown; set "show_deleted" to
  384. Xinclude deleted messages.
  385. X
  386. XThe command ":c" is equivalent to "headers -H:c".  The -H can be
  387. Xomitted, i.e., "headers :c" will also work.
  388. X%%
  389. X
  390. X%hdr_format%
  391. XThis variable controls the display of message headers.  Use:
  392. X    set hdr_format="string"
  393. Xto change the header display.  The string uses printf style
  394. Xformatting and follows these conventions:
  395. X    %a  address of the author
  396. X    %c  number of characters (bytes) in the message
  397. X    %d  entire date of the message (see "date_received" variable)
  398. X    %f  "From" field (author name and address)
  399. X    %i  the message-id (may or may not be present)
  400. X    %l  number of lines in the message
  401. X    %M  month name of the message
  402. X    %N  day of the month (number)
  403. X    %n  name of the author
  404. X    %s  subject of the message
  405. X    %t  "To" field (recipients)
  406. X    %T  time of the message (see "mil_time" variable)
  407. X    %W  day of the week (Sun, Mon, etc.)
  408. X    %Y  year of the message 
  409. X    %y  year (last 2 digits only)
  410. X    \n  a newline
  411. X    \t  a tab
  412. X
  413. XA field specifier may be used in any % expansion.  Thus, "%20s"
  414. Xwill print the first 20 characters of the Subject.  No matter
  415. Xwhat the formatting string, the message number, the status of
  416. Xthe message and a '>' (if this is the "current" message) is
  417. Xbefore any user defined format is printed.
  418. X%%
  419. X
  420. X%folder%
  421. X      folder/update [-N] [-r] [!] [%[user]|#|&|file]
  422. X  -N       Do not display the list of headers
  423. X  -r       read only mode (cannot write changes to this folder)
  424. X  %[user]  change to /usr/spool/mail/[user] (you by default)
  425. X  #        change to folder accessed previous to current folder
  426. X  &        change to "mbox" -- default is $mbox or ~/mbox
  427. X
  428. XThe "folder" command changes the current folder; with no parameters,
  429. Xit prints the name of the current folder.  If `!' is specified, the
  430. Xcurrent folder is not updated before changing.
  431. X
  432. XThe "update" command updates the current folder.  In this case, only
  433. Xthe -N and -r options are observed.
  434. X%%
  435. X
  436. X%prompt%
  437. XThis variable controls the prompt that mush will display.
  438. X    set prompt = "string"
  439. XThe "string" follows printf style formatting conventions:
  440. X    %F  full path of the current working folder
  441. X    %f  name (path tail) of the current folder
  442. X    %m  current message number
  443. X    %n  number of new messages
  444. X    %u  number of unread messages
  445. X    %d  number of deleted messages
  446. X    %t  total number of messages
  447. X    %T  current time
  448. X    %N  day of the month (number) (today)
  449. X    %W  weekday name (today)
  450. X    %M  month name (this month)
  451. X    %Y  year (this year)
  452. X    %y  year (last 2 digits only)
  453. X    \n  newline
  454. X    \t  tab
  455. X%%
  456. X
  457. X%quit%
  458. X      quit/exit
  459. X
  460. XThese commands end a mush session.  "quit" will update your
  461. Xmailbox; if new mail has come in, you will be told so and given
  462. Xan option whether to really quit or not.  "exit" will leave mush
  463. Xneither updating your mailbox nor checking for new mail.
  464. X%%
  465. X
  466. X%ls%
  467. XThe "ls" command is exactly like the UNIX command "ls".  All
  468. Xparameters are the same.  The variable "lister" can be set to
  469. Xa list of default parameters, thus avoiding having to specify
  470. Xthem all the time.  The "folders" command is equivalent to
  471. Xdoing "ls $folder" from the Mush prompt.
  472. X%%
  473. X
  474. X%shell%
  475. X      sh [command]
  476. X
  477. XIf a "command" is given, that UNIX command will be executed
  478. Xunder the Bourne shell.  If no command is specified, then an
  479. Xinteractive shell will be started. The environment variable
  480. XSHELL or the local mail shell variable shell  describes the
  481. Xshell to invoke.  If none is set, then the default shell is
  482. Xdefined by the system administrator (currently set to csh).
  483. X
  484. XUsers on systems with job control will probably have little
  485. Xuse for the sh command.
  486. X%%
  487. X
  488. X%stop%
  489. XThe stop command sends a stop signal to the mail shell.  It is
  490. Xequivalent to ^Z as it will stop the process.  Since the shell
  491. Xnever needs to be exited, the command 'q' may be aliased to
  492. X"stop" and the shell may have
  493. X    alias mail %mush
  494. X(assumes csh) which will bring mush into the foreground rather
  495. Xthan having to invoke a new shell.  New mail will be read into
  496. Xthe shell automatically and much time and energy is saved.
  497. X%%
  498. X
  499. X%curses%
  500. XThe curses-based interface for Mush does not require a graphics
  501. Xdisplay, but does requires a terminal which can handle upline
  502. Xcursor movement capabilities.  All commands are one or two
  503. Xkeystroke commands and are executed as soon as the key is typed.
  504. X
  505. XFor a list of current key-to-command bindings, use the "bind"
  506. Xcommand (defaults to 'b' in curses mode).
  507. X%%
  508. X
  509. X%bind%
  510. X      bind <sequence> <curses-command> [ <parameters> ]
  511. X
  512. XBinding is done for the curses interface only.  It allows the
  513. Xuser to bind keystrokes or key sequences to curses-interface
  514. Xcommands.  You cannot bind keystrokes to regular mush commands
  515. Xusing bind.
  516. X
  517. XA bound key-sequence (input by the user) will be converted into
  518. Xthe curses command it is bound to.  For a list of all curses
  519. Xcommands, issue the "bind" command and follow the instructions
  520. Xto get a list.  Currently, parameters are ignored for all curses
  521. Xcommands except the special command "macro".
  522. X
  523. XWhen specifying sequences, you may enter almost anything at the
  524. Xkeyboard that you want to type.  This includes most control
  525. Xcharacters.  A special syntax is provided to specify control
  526. Xcharacters if you wish to set up default key bindings in your
  527. Xinitialization file without using real control characters.
  528. X
  529. XTo bind keystrokes that are control characters in the
  530. Xinitialization file, you must use the notation "\CX" where "X"
  531. Xis an upper-case letter representing the control key you want to
  532. Xuse. "\CN" would be control-N; "\n" is carriage return.  You may
  533. Xnot bind keyboard generated signals; for most users, those key
  534. Xsequences are control-C and control-\.  For users with job
  535. Xcontrol, the suspend characters (usually control-Z and
  536. Xcontrol-Y) are also ignored.
  537. X
  538. XTo specify the escape key, use "\E"; "\C[" will not work.
  539. X
  540. XTrying to bind a key sequence which prefixes another sequence is
  541. Xan error and the user is warned that the longer binding will not
  542. Xwork.  The binding will take place, however, because it is
  543. Xpossible to unbind the shorter sequence, thus validating the
  544. Xlonger sequence.
  545. X
  546. XThe special curses command "macro" allows a string to be
  547. Xexecuted just as if the user typed it directly.  Issue the
  548. X"bind-macro" command for more details.
  549. X%%
  550. X
  551. X%msg_flags%
  552. X      flags [msg_list] [[+|-] [D N O P R S r U]]
  553. X
  554. XThis command displays the status of messages by default.
  555. XIf a list is specified, it will tell which bits of the
  556. Xmessage are set: Delete, New, Old, Preserved, Read, Saved
  557. Xreplied-to, and Unread.  If any (one or more) of the bits
  558. Xare given and no + or - modifier is specified, then the
  559. Xstatus of each message in the list will be set to that
  560. Xstatus absolutely (other status flags are lost).  However,
  561. Xif a + or - is specified, then the status is modified for
  562. Xthat bit to on (+) or off (-).
  563. X
  564. XIf no list is given, then the list of messages is taken
  565. Xfrom a pipe (if piped) or the current message is used.
  566. X%%
  567. X
  568. X%setenv%
  569. X      setenv VARIABLE [value]
  570. X
  571. XVariable names may be any string, but traditionally environment
  572. Xvariables are all upper case.  If no "value" is specified, then
  573. Xthe variable name will be set to an empty string.  If the value
  574. Xcontains spaces, you should enclose the string in quotation
  575. Xmarks.  Use printenv to print a list of all your environment
  576. Xvariables.
  577. X%%
  578. X
  579. X%unsetenv%
  580. X      unsetenv VARIABLE
  581. X
  582. XYou must specify one and only one variable to unset in your
  583. Xenvironment variable settings.  Use printenv to print a list of
  584. Xall your environment variables.
  585. X%%
  586. X
  587. X%edit_msg%
  588. X      edit_msg [msg_list]
  589. X
  590. XThe "edit_msg" command lets you edit messages in your folder.
  591. XWhen editing messages, be careful not to remove certain message
  592. Xheaders such as Date:, From:, or any others that look important.
  593. XIf you remove or change something you shouldn't have, you will
  594. Xbe notified and the temporary file used to edit the message will
  595. Xnot be removed.
  596. X%%
  597. X
  598. X%bind-macro%
  599. X      bind-macro [<sequence> [<expansion>]]
  600. X
  601. XThe "bind-macro" command allows you to set macros in curses
  602. Xmode, so that one keystroke (or a few) will act as though you
  603. Xhad typed a longer sequence.  Using "bind-macro" is equivalent
  604. Xto specifying the "macro" special command as a parameter to
  605. Xthe "bind" command.
  606. X
  607. XGiven no parameters, "bind-macro" will list all current curses
  608. Xmode macros.  Given only a <sequence>, it will show the current
  609. Xbinding for that sequence.  Given both a <sequence> and an
  610. X<expansion>, it will create a macro such that, when the
  611. X<sequence> is typed in curses mode, the effect will be the same
  612. Xas if the <expansion> had been typed instead.
  613. X
  614. XThe same format for control characters that is used for the
  615. X"bind" command may be used in both the <sequence> and the
  616. X<expansion>, i.e.,
  617. X    \Cx     control-x (where x is a capital letter)
  618. X    \E      the escape character (\C[ does NOT work!)
  619. X    \n      a newline (other C-style escapes also work)
  620. X
  621. XExample:
  622. X    bind-macro F [folder]+record\n
  623. X
  624. XIf you are in curses mode and hit the F key, then the curses
  625. Xmode command "folder" will execute and +record (followed by
  626. Xa carriage return) will be entered as if you typed it.
  627. X
  628. XAlso see the "map" and "map!" commands.
  629. X%%
  630. X
  631. X%map%
  632. X      map [<sequence> [<expansion>]]
  633. X
  634. XThe "map" command allows you to use one keystroke (or a few) and
  635. Xhave it act as though you had typed a longer sequence.
  636. X
  637. XGiven no parameters, "map" will list all current line mode
  638. Xmacros.  Given only a <sequence>, it will show the current
  639. Xbinding for that sequence.  Given both a <sequence> and an
  640. X<expansion>, it will create a macro such that, when the
  641. X<sequence> is typed in line mode, the effect will be the same
  642. Xas if the <expansion> had been typed instead.
  643. X
  644. XThe same format for control characters that is used for the
  645. X"bind" command may be used in both the <sequence> and the
  646. X<expansion>, i.e.,
  647. X    \Cx     control-x (where x is a capital letter)
  648. X    \E      the escape character (\C[ does NOT work!)
  649. X    \n      a newline (other C-style escapes also work)
  650. X
  651. XExample:
  652. X    map & print\n
  653. X
  654. XIf you are not in curses mode and hit the & key, then it will
  655. Xbe as if you typed the word "print" and hit carriage return.
  656. X
  657. XTo type a character without having the mapping expanded, precede
  658. Xthe character with a backslash (\).
  659. X
  660. XAlso see the "map!" and "bind" commands.
  661. X%%
  662. X
  663. X%map!%
  664. X      map! [<sequence> [<expansion>]]
  665. X
  666. XThe "map!" command allows you to set macros in message
  667. Xcomposition mode, so that one keystroke (or a few) will act
  668. Xas though you had typed a longer sequence.  map!'s take
  669. Xeffect regardless of whether you started the letter from
  670. Xcurses mode or line mode.
  671. X
  672. XGiven no parameters, "map!" will list all composition mode
  673. Xmacros.  Given only a <sequence>, it will show the current
  674. Xbinding for that sequence.  Given both a <sequence> and an
  675. X<expansion>, it will create a macro such that, when the
  676. X<sequence> is typed in message composition mode, the effect will
  677. Xbe the same as if the <expansion> had been typed instead.
  678. X
  679. XThe same format for control characters that is used for the
  680. X"bind" command may be used in both the <sequence> and the
  681. X<expansion>, i.e.,
  682. X    \Cx     control-x (where x is a capital letter)
  683. X    \E      the escape character (\C[ does NOT work!)
  684. X    \n      a newline (other C-style escapes also work)
  685. X
  686. XExample:
  687. X    map! ! <BANG>
  688. X
  689. XIf you are typing in a letter regardless of which interface you
  690. Xuse and you hit the ! key, then it would be as if you typed the
  691. Xkeys "<BANG>".
  692. X
  693. XTo type a character without having the mapping expanded, precede
  694. Xthe character with a backslash (\).
  695. X
  696. XAlso see the "bind" and "map" commands.
  697. X%%
  698. X
  699. X%eval%
  700. X      eval args ...
  701. X
  702. XThis command causes its arguments to be re-parsed and then
  703. Xexecuted as a mush command.  Example:
  704. X    set initprompt='"$hostname:$cwd "'
  705. X    eval set prompt=$initprompt
  706. X%%
  707. X
  708. X%pipe_msg%
  709. X      pipe [msg-list] unix-command
  710. X
  711. XThe specified unix-command is executed.  The standard input of
  712. Xthe command is the texts of listed messages, including headers
  713. Xthat are not ignored (see "ignore -?" and "set ?show_hdrs").  If
  714. Xthis command is part of a mush pipeline (|) then any list of
  715. Xmessages given is added to those taken from the pipeline.  If no
  716. Xmsg-list is given and there is no pipeline, the current message
  717. Xis used.  The unix-command is executed via "sh", so csh aliases
  718. Xmay not be used.
  719. X
  720. XIf invoked with a capital letter (Pipe), only the bodies of the
  721. Xmessages will be fed to the unix-command -- all headers will be
  722. Xomitted.
  723. X
  724. XExamples:
  725. X    pipe 2 7 more      -- send messages 2 and 7 through "more"
  726. X    pipe patch         -- send the current message to "patch"
  727. X    1 | Pipe nroff     -- send the body of message 1 to "nroff"
  728. X%%
  729. X
  730. X%merge%
  731. X      merge [-N] folder-name
  732. X
  733. XThe contents of the specified folder are read into the current
  734. Xfolder.  If -N is not specified, a header summary is printed
  735. Xfor each message read (see "headers -?").
  736. X
  737. XA list of all the merged messages is returned for use in pipes.
  738. X%%
  739. X
  740. X%echo%
  741. X    echo [-n] [-h | -p] args
  742. X
  743. XEcho simply echoes the parameters to the command back to the user.
  744. X
  745. XIf the -n flag is given, then no newline is appended.
  746. XIf the -h flag is given, then echo looks for formatting parameters
  747. Xas if the "from" command were given on the "current" message.
  748. XIf the -p flag is given, then echo looks for formatting parameters
  749. Xas if your prompt were changed temporarily.
  750. X
  751. XExamples:
  752. X    echo -h This message is from %a and is dated %d
  753. Xmight produce:
  754. X    This message is from island!argv and is dated Dec 14, 1988.
  755. X
  756. X    echo -p There are %n new messages to read in %f.
  757. Xmight produce:
  758. X    There are 5 new messages to read in /usr/spool/mail/argv.
  759. X
  760. XNote that -h and -p cannot be specified together.
  761. X%%
  762. X
  763. X%undigest%
  764. X    undigest [-m] [msg_list] [filename]
  765. X
  766. XA "digest" is a mail message which is a collection of other mail messages
  767. Xmailed to a "moderator" by other users.  The moderator compiles all the
  768. Xmessages into a folder and sends the result to all the subscribers of the
  769. Xmailing list.  The undigest command disassembles the entries into the set
  770. Xof messages which comprises the digest.
  771. X
  772. XThe -m option will merge these messages into the current folder.  Otherwise,
  773. Xif a filename is specified, a new folder is created and the user can change
  774. Xfolders to read the messages separately.
  775. X
  776. XIf a message list is specified, each digest is disassembled to the same
  777. Xfilename (if given).  If no filename is given and the user did not request
  778. Xa merge, then a folder is created based on the subject of the digest.
  779. X%%
  780. END_OF_FILE
  781. if test 27197 -ne `wc -c <'cmd_help'`; then
  782.     echo shar: \"'cmd_help'\" unpacked with wrong size!
  783. fi
  784. # end of 'cmd_help'
  785. fi
  786. if test -f 'msgs.c' -a "${1}" != "-c" ; then 
  787.   echo shar: Will not clobber existing file \"'msgs.c'\"
  788. else
  789. echo shar: Extracting \"'msgs.c'\" \(24063 characters\)
  790. sed "s/^X//" >'msgs.c' <<'END_OF_FILE'
  791. X/* @(#)msgs.c    (c) copyright 10/18/86 (Dan Heller) */
  792. X
  793. X#include "mush.h"
  794. X
  795. Xvoid
  796. Xdisplay_msg(n, flg)
  797. Xregister int n;
  798. Xlong flg;
  799. X{
  800. X    if (ison(msg[n].m_flags, DELETE) && !do_set(set_options, "show_deleted")) {
  801. X    print("Message %d deleted; ", n+1);
  802. X#ifdef SUNTOOL
  803. X    if (istool)
  804. X        print_more("Select UNDELETE to read."), do_clear();
  805. X    else
  806. X#endif /* SUNTOOL */
  807. X    if (iscurses)
  808. X        print_more("Type 'u' to undelete.");
  809. X    else
  810. X        print("Type 'undelete %d' to undelete\n", n+1);
  811. X    return;
  812. X    }
  813. X    set_isread(n);
  814. X    if (ison(flg, M_TOP)) {
  815. X    turnon(flg, NO_HEADER);
  816. X    print("Top of "), turnon(glob_flags, CONT_PRNT);
  817. X    }
  818. X
  819. X#ifdef MMDF
  820. X    turnon(flg, NO_SEPARATOR);
  821. X#endif /* MMDF */
  822. X    if (!istool && isoff(flg, NO_PAGE) &&
  823. X        crt < msg[n].m_lines && isoff(flg, M_TOP)) {
  824. X    char buf[32], *pager = do_set(set_options, "pager");
  825. X    if (!pager)
  826. X        pager = DEF_PAGER;
  827. X    if (!*pager || !strcmp(pager, "internal"))
  828. X        pager = NULL; /* default to internal pager if pager set to "" */
  829. X    (void) do_pager(pager, TRUE); /* start pager */
  830. X    (void) do_pager(sprintf(buf, "Message #%d (%d lines)\n",
  831. X             n+1, msg[n].m_lines), FALSE);
  832. X    (void) copy_msg(n, NULL_FILE, flg);
  833. X    (void) do_pager(NULL, FALSE); /* end pager */
  834. X    } else {
  835. X    print("Message #%d (%d lines)\n", n+1, msg[n].m_lines);
  836. X    (void) copy_msg(n, stdout, flg);
  837. X    }
  838. X}
  839. X
  840. X/*
  841. X * copy message 'n' to file "fp" according to various flag arguments
  842. X * return number of lines copied or -1 if system error on fputs.
  843. X * If "fp" is null, send to internal pager.  This can only happen from
  844. X * display_msg above.
  845. X */
  846. Xcopy_msg(n, fp, flags)
  847. Xregister int n;
  848. Xregister FILE *fp;
  849. Xu_long flags;
  850. X{
  851. X    register int  ignoring = 0, lines = 0;
  852. X    register char *indent_str;
  853. X    int  on_hdr = 1, top, squeeze = 0;
  854. X    char       line[BUFSIZ], *show_hdrs = NULL;
  855. X
  856. X    still_more = 0;
  857. X    if (ison(flags, M_TOP)) {
  858. X    register char *p = do_set(set_options, "toplines");
  859. X    top = (p)? atoi(p) : crt;
  860. X    }
  861. X    /* When updating to a folder, always write all headers! */
  862. X    if (ison(flags, UPDATE_STATUS))
  863. X    turnon(flags, NO_IGNORE);
  864. X    else if (do_set(set_options, "alwaysignore"))
  865. X    turnoff(flags, NO_IGNORE);
  866. X    if (isoff(flags, NO_IGNORE)) {
  867. X    if (do_set(set_options, "squeeze"))
  868. X        squeeze = 1;
  869. X    show_hdrs = do_set(set_options, "show_hdrs");
  870. X    }
  871. X
  872. X#ifdef SUNTOOL
  873. X    if (istool && (!fp || fp == stdout)) {
  874. X    register int x = (msg[n].m_lines + 2) * l_height(curfont);
  875. X
  876. X    if (x > 32765) { /* to overcome a bug in pixrects that sun won't fix */
  877. X        print("message too big to display using this font");
  878. X        return 0;
  879. X    }
  880. X    if (x < msg_rect.r_height) /* make it at least as big as the window */
  881. X        x = msg_rect.r_height;
  882. X    /* If the window isn't big enough, an infinite loop occurs in Addstr */
  883. X    if (x < 2 * l_height(curfont) || msg_rect.r_width < 3*l_width(curfont))
  884. X        return 0;
  885. X    do_clear();
  886. X    lock_cursors();
  887. X    /* msg_pix is for Addstr() */
  888. X    if (!(msg_pix = mem_create(msg_rect.r_width, x, 1))) {
  889. X        error("mem_create");
  890. X        return 0;
  891. X    }
  892. X    pr_rop(msg_pix, 0,0, msg_rect.r_width-1, x-1, PIX_CLR, 0,0,0);
  893. X    on_hdr = 1;
  894. X    }
  895. X#endif /* SUNTOOL */
  896. X    if (ison(flags, INDENT)) {
  897. X    if ((indent_str = do_set(set_options, "pre_indent_str"))) {
  898. X        char *old_fmt = hdr_format;
  899. X        hdr_format = indent_str;
  900. X        fprintf(fp, "%s\n", compose_hdr(n) + 9); /* magic number 9 !! */
  901. X        hdr_format = old_fmt;
  902. X    }
  903. X    if (!(indent_str = do_set(set_options, "indent_str")))
  904. X        indent_str = DEF_INDENT_STR;
  905. X    }
  906. X    /* "line" used as dummy here, since 0 bytes read */
  907. X    if (!msg_get(n, line, 0)) {
  908. X    error("Unable to find msg %d", n+1);
  909. X    return -1;
  910. X    }
  911. X    while (still_more < msg[n].m_size && fgets(line, sizeof (line), tmpf)) {
  912. X    still_more += strlen(line);
  913. X#ifdef MMDF
  914. X    if (ison(flags, NO_SEPARATOR)) {
  915. X        if (!strncmp(line, MSG_SEPARATOR, 4))
  916. X        continue;
  917. X    }
  918. X#endif /* MMDF */
  919. X    /*
  920. X     * If squeeze is one, all blanks lines squeeze down to one blank line.
  921. X     * If squeeze is two, squeezing is in progress so wait for the next \n.
  922. X     */
  923. X    if (*line == '\n') {
  924. X        if (on_hdr)    /* blank line -- end of header */
  925. X        turnoff(flags, NO_HEADER), on_hdr = 0;
  926. X        if (squeeze > 1)
  927. X        continue;
  928. X        else if (squeeze)
  929. X        squeeze = 2;
  930. X    } else if (squeeze > 1)
  931. X        squeeze = 1;
  932. X
  933. X    if (ison(flags, UPDATE_STATUS))
  934. X        if (!strncmp(line, "Status:", 7))
  935. X        continue; /* ignore this and other "Status" lines */
  936. X        else if (!on_hdr) {
  937. X        /* preserve NEW/UNREAD status on preserved messages */
  938. X        register char *p = line;
  939. X        p += Strcpy(p, "Status: O");
  940. X        if (isoff(msg[n].m_flags, UNREAD) &&
  941. X            isoff(msg[n].m_flags, PRESERVE))
  942. X            *p++ = 'R';
  943. X        if (ison(msg[n].m_flags, SAVED))
  944. X            *p++ = 'S';
  945. X        if (ison(msg[n].m_flags, REPLIED))
  946. X            *p++ = 'r';
  947. X        *p++ = '\n', *p = 0;
  948. X        fputs(line, fp);
  949. X        (void) strcpy(line, "\n");
  950. X        turnoff(flags, UPDATE_STATUS);
  951. X        }
  952. X    if (on_hdr && (isoff(flags, NO_IGNORE) || ison(flags, FORWARD))) {
  953. X        register char *p = any(line, " \t:");
  954. X        if (!p)
  955. X        ignoring = 0, on_hdr = 0;
  956. X        else if (ignoring)
  957. X        if (*p != ':') {
  958. X            Debug("Ignoring: %s", line);
  959. X            continue;
  960. X        } else
  961. X            ignoring = 0;
  962. X        if (p && *p == ':') {
  963. X        *p = 0;
  964. X        ignoring = 0;
  965. X        if (show_hdrs) {
  966. X            if (!chk_two_lists(line, show_hdrs, ":, \t"))
  967. X            ignoring = 1;
  968. X        } else if (ison(flags, FORWARD)) {
  969. X            if (chk_two_lists(line, IGNORE_ON_FWD, ":, \t"))
  970. X            ignoring = 1;
  971. X        } else {
  972. X            register struct options *opts;
  973. X            for (opts = ignore_hdr; opts; opts = opts->next)
  974. X            if (!lcase_strncmp(opts->option, line, -1)) {
  975. X                ignoring = 1;
  976. X                break;
  977. X            }
  978. X        }
  979. X        *p = ':';
  980. X        if (ignoring) {
  981. X            Debug("Ignoring: %s", line);
  982. X            continue;
  983. X        }
  984. X        }
  985. X    }
  986. X    if (!on_hdr && ison(flags, M_TOP) && !--top)
  987. X        break;
  988. X    if (isoff(flags, NO_HEADER)) {
  989. X        /* note that function returns the number of lines */
  990. X        lines++;
  991. X#ifdef SUNTOOL
  992. X        if (istool && (!fp || fp == stdout)) {
  993. X        Addstr(line);
  994. X        continue;
  995. X        }
  996. X#endif /* SUNTOOL */
  997. X        if (ison(flags, INDENT))
  998. X        fputs(indent_str, fp);
  999. X        if (!fp) {
  1000. X        if (do_pager(line, FALSE) == EOF)
  1001. X            return -1;
  1002. X        } else if (fputs(line, fp) == EOF)
  1003. X        /* Pipe broken, out of file space, etc */
  1004. X        return -1;
  1005. X    }
  1006. X    }
  1007. X    if (ison(flags, INDENT) &&
  1008. X    (indent_str = do_set(set_options, "post_indent_str")) && *indent_str) {
  1009. X    char *old_fmt = hdr_format;
  1010. X    hdr_format = indent_str;
  1011. X    fprintf(fp, "%s\n", compose_hdr(n)+9); /* magic number 9 !! */
  1012. X    hdr_format = old_fmt;
  1013. X    }
  1014. X#ifdef SUNTOOL
  1015. X    if (istool && (!fp || fp == stdout)) {
  1016. X    unlock_cursors();
  1017. X    txt.y = still_more = msg_rect.r_height;
  1018. X    scroll_win(0);  /* causes a display */
  1019. X    }
  1020. X#endif /* SUNTOOL */
  1021. X    return lines;
  1022. X}
  1023. X
  1024. X/*
  1025. X * copy tempfile back to folder.
  1026. X * Return 1 on success, 0 on failure.
  1027. X */
  1028. Xcopyback(prompt)
  1029. Xchar *prompt;
  1030. X{
  1031. X    register int    i=0, j=0, k=0;
  1032. X    register long    flg = 0;
  1033. X    register FILE    *mbox = NULL_FILE, *mail_fp = NULL_FILE;
  1034. X#ifndef DOT_LOCK
  1035. X#ifdef SYSV
  1036. X    FILE         *save_mail_fp = NULL_FILE;
  1037. X#endif /* SYSV */
  1038. X#endif /* !DOT_LOCK */
  1039. X    char        *mbox_file, action = 0;
  1040. X    int         hold = 0, delete_it = 0, dont_unlink = FALSE;
  1041. X    int            isspool, keepsave;
  1042. X    static int        first = 1;
  1043. X
  1044. X    /*
  1045. X     * if there is new mail in this folder, the user is notified and
  1046. X     * prompted if he really wants to update the folder.  He's either
  1047. X     * quitting or changing folders, so let him read the new mail first.
  1048. X     */
  1049. X    if (!first && check_new_mail() > 0) {
  1050. X    if (!istool) {
  1051. X        char buf[16];
  1052. X        if (iscurses)
  1053. X        putchar('\n'), turnon(glob_flags, CNTD_CMD);
  1054. X        print("%s [n] ", prompt);
  1055. X        buf[0] = 0;
  1056. X        if (!Getstr(buf, sizeof (buf), 0) || lower(*buf) != 'y')
  1057. X        return 0;
  1058. X    }
  1059. X    }
  1060. X    first = 0;
  1061. X
  1062. X    /* If the user hasn't changed anything, just return true */
  1063. X    if (isoff(glob_flags, DO_UPDATE))
  1064. X    return 1;
  1065. X    if (ison(glob_flags, READ_ONLY)) {
  1066. X    print("Unable to update %s: read only\n", mailfile);
  1067. X    return 0; /* user should use "exit" instead of "quit". */
  1068. X    }
  1069. X    if (!msg_cnt) /* prevent unnecessary overwrite */
  1070. X    return 1;
  1071. X
  1072. X#ifdef SUNTOOL
  1073. X    if (istool) {
  1074. X    timerclear(&(mail_timer.it_interval));
  1075. X    timerclear(&(mail_timer.it_value));
  1076. X    }
  1077. X#endif /* SUNTOOL */
  1078. X
  1079. X    /* open mbox if: "autodelete" AND "hold" are NOT set. */
  1080. X    if (!strcmp(mailfile, spoolfile)
  1081. X        && !(delete_it = !!do_set(set_options, "autodelete"))
  1082. X        && !(hold = !!do_set(set_options, "hold"))) {
  1083. X    register char *p;
  1084. X    int x = 1; /* tell getpath to ignore "ENOENT" if file not found */
  1085. X
  1086. X    if (!(p = do_set(set_options, "mbox")))
  1087. X        p = DEF_MBOX;
  1088. X    mbox_file = getpath(p, &x);
  1089. X    if (x) {
  1090. X        if (x > 0)
  1091. X        print("%s is a directory.\n", mbox_file);
  1092. X        else
  1093. X        print("Unable to open %s: %s\n", p, mbox_file);
  1094. X        mbox = NULL_FILE;
  1095. X    } else {
  1096. X        if (Access(mbox_file, F_OK) == -1) /* does it exist? */
  1097. X        mbox = mask_fopen(mbox_file, "w");
  1098. X        else
  1099. X        mbox = mask_fopen(mbox_file, "a");
  1100. X        if (!mbox)
  1101. X        error("Unable to write to %s", mbox_file);
  1102. X    }
  1103. X    }
  1104. X#ifdef DOT_LOCK
  1105. X    if ((i = dot_lock(mailfile)) == 0)
  1106. X#endif /* DOT_LOCK */
  1107. X#ifdef DOT_LOCK
  1108. X    mail_fp = mask_fopen(mailfile, "w+");
  1109. X#else /* !DOT_LOCK */
  1110. X    /* We can't lock a file unless we have an fd, but "w+" will zero
  1111. X     * the file.  If the lock later failed for any reason (possible
  1112. X     * race condition with an MTA), we would lose all current mail.
  1113. X     * So, open read/write (if possible) and truncate later.
  1114. X     */
  1115. X    mail_fp = mask_fopen(mailfile, "r+");
  1116. X#endif /* DOT_LOCK */
  1117. X    if (!mail_fp) {
  1118. X    error("Unable to rewrite %s", mailfile);
  1119. X    if (mbox)
  1120. X        fclose(mbox);
  1121. X    return 0;
  1122. X    }
  1123. X    if (i != 0 || lock_file(mailfile, mail_fp) == -1) {
  1124. X#ifndef DOT_LOCK
  1125. X    error("WARNING: unable to lock %s", mailfile);
  1126. X#endif /* DOT_LOCK */
  1127. X    if (mail_fp)
  1128. X        close_lock(mailfile, mail_fp);
  1129. X    if (mbox)
  1130. X        fclose(mbox);
  1131. X    return 0;
  1132. X    }
  1133. X#if !defined(DOT_LOCK) && defined(SYSV)
  1134. X    /* SysV can't truncate a file in the middle, so we can't just
  1135. X     * write to mail_fp and close.  Instead, we save the mail_fp
  1136. X     * and reopen for writing, ignoring our own lock.  After updating,
  1137. X     * we can safely fclose both file pointers.
  1138. X     */
  1139. X    save_mail_fp = mail_fp;
  1140. X    /* This could fail if we run out of file descriptors */
  1141. X    if (!(mail_fp = fopen(mailfile, "w"))) {
  1142. X    error("WARNING: unable to reopen %s for update", mailfile);
  1143. X    if (save_mail_fp)
  1144. X        close_lock(mailfile, save_mail_fp);
  1145. X    if (mbox)
  1146. X        fclose(mbox);
  1147. X    return 0;
  1148. X    }
  1149. X#endif /* SYSV && !DOT_LOCK */
  1150. X
  1151. X    print("Updating \"%s\"", mailfile);
  1152. X
  1153. X    turnon(flg, UPDATE_STATUS);
  1154. X    turnon(glob_flags, IGN_SIGS);
  1155. X
  1156. X    keepsave = !!do_set(set_options, "keepsave");
  1157. X    isspool = !strcmp(mailfile, spoolfile);
  1158. X
  1159. X    for (i = 0; i < msg_cnt; i++)
  1160. X    /* check to see if message is marked for deletion or, if read and not
  1161. X     * preserved, delete it if autodelete is set. Otherwise, save the
  1162. X     * message in the spool file if hold is set. If all fails, save in mbox.
  1163. X     */
  1164. X    if (ison(msg[i].m_flags, DELETE)
  1165. X    ||  ison(msg[i].m_flags, SAVED) && !keepsave &&
  1166. X        isoff(msg[i].m_flags, PRESERVE) && isspool
  1167. X    ||  isoff(msg[i].m_flags, UNREAD) && isoff(msg[i].m_flags, PRESERVE) 
  1168. X        && delete_it) {
  1169. X        Debug("%s %d",
  1170. X        (action!='d')? "\ndeleting message:" : "", i+1), action = 'd';
  1171. X        continue;
  1172. X    } else if (ison(msg[i].m_flags, UNREAD) ||
  1173. X         ison(msg[i].m_flags, PRESERVE) || hold || !mbox) {
  1174. X        j++;
  1175. X        Debug("%s %d",
  1176. X        (action!='s')? "\nsaving in spool:" : "", i+1), action = 's';
  1177. X        if (copy_msg(i, mail_fp, flg) == -1) {
  1178. X        error("WARNING: unable to write back to spool");
  1179. X        print("ALL mail left in %s\n", tempfile);
  1180. X        print("Spool mailbox may be corrupted.\n");
  1181. X        dont_unlink = TRUE;
  1182. X        break;
  1183. X        }
  1184. X    } else if (isspool) {   /* copy back to mbox */
  1185. X        k++;
  1186. X        if (copy_msg(i, mbox, flg) == -1) {
  1187. X        error("WARNING: unable to write to mbox");
  1188. X        print("Unresolved mail left in %s\n", tempfile);
  1189. X        dont_unlink = TRUE;
  1190. X        break;
  1191. X        }
  1192. X        Debug("%s %d",
  1193. X        (action!='m')? "\nsaving in mbox:" : "", i+1), action = 'm';
  1194. X    }
  1195. X    Debug("\n%s", mailfile);
  1196. X
  1197. X#ifndef DOT_LOCK
  1198. X#ifdef SYSV
  1199. X    /* Close the write file pointer first */
  1200. X    fclose(mail_fp);
  1201. X    mail_fp = save_mail_fp;
  1202. X#else /* !SYSV */
  1203. X    /* Truncate the file at the end of what we just wrote.
  1204. X     * If you aren't SYSV and you still can't ftruncate(),
  1205. X     * you're out of luck?
  1206. X     */
  1207. X    (void) ftruncate(fileno(mail_fp), ftell(mail_fp));
  1208. X#endif /* SYSV */
  1209. X#endif /* !DOT_LOCK */
  1210. X
  1211. X    close_lock(mailfile, mail_fp);
  1212. X
  1213. X#ifdef SUNTOOL
  1214. X    if (istool) {
  1215. X    mail_timer.it_value.tv_sec = time_out;
  1216. X    setitimer(ITIMER_REAL, &mail_timer, NULL);
  1217. X    }
  1218. X#endif /* SUNTOOL */
  1219. X
  1220. X    /* some users like to have zero length folders for frequent usage */
  1221. X    if (mbox)
  1222. X    fclose(mbox);
  1223. X    if (j) {
  1224. X    long times[2];
  1225. X    times[1] = time(×[0]) - (long)2;
  1226. X    if (!strcmp(mailfile, spoolfile) && utime(mailfile, times))
  1227. X        error("utime");
  1228. X    print_more(": saved %d message%s\n", j, (j==1)? NO_STRING: "s");
  1229. X    } else
  1230. X#ifdef HOMEMAIL
  1231. X    if (!dont_unlink && !do_set(set_options, "save_empty"))
  1232. X#else /* HOMEMAIL */
  1233. X    if (strcmp(mailfile, spoolfile) && !dont_unlink &&
  1234. X    !do_set(set_options, "save_empty"))
  1235. X#endif /* HOMEMAIL */
  1236. X    if (unlink(mailfile))
  1237. X        turnon(glob_flags, CONT_PRNT), error(": cannot remove");
  1238. X    else
  1239. X        print_more(": removed\n");
  1240. X    else
  1241. X    print_more(": empty\n");
  1242. X    if (k)
  1243. X    print("saved %d message%s in %s\n",k,(k==1)? NO_STRING:"s", mbox_file);
  1244. X
  1245. X    turnoff(glob_flags, IGN_SIGS);
  1246. X
  1247. X    return 1;
  1248. X}
  1249. X
  1250. X/*
  1251. X * check the sizes of the current folder (file) and the spool file.
  1252. X * spool_size is the size in bytes of the user's main mailbox.
  1253. X * last_size is the size of the _current_ folder the last time we checked.
  1254. X * return true if the current folder has new mail.  check_new_mail() checks
  1255. X * for new mail in the system mailbox since it checks against last_spool_size.
  1256. X */
  1257. Xmail_size()
  1258. X{
  1259. X    struct stat buf;
  1260. X    if (strcmp(mailfile, spoolfile) && !stat(spoolfile, &buf))
  1261. X    spool_size = buf.st_size;
  1262. X    if (!*mailfile)
  1263. X    return 0;
  1264. X    if (stat(mailfile, &buf)) {
  1265. X    if (errno != ENOENT)
  1266. X        error("Unable to stat %s", mailfile);
  1267. X    return 0;
  1268. X    }
  1269. X    if (!strcmp(mailfile, spoolfile))
  1270. X    spool_size = buf.st_size;
  1271. X    if (buf.st_size != last_size) {
  1272. X    last_size = buf.st_size;
  1273. X    return 1;
  1274. X    }
  1275. X    return 0;
  1276. X}
  1277. X
  1278. Xvoid
  1279. Xmail_status(as_prompt)
  1280. X{
  1281. X    static char buf[256];
  1282. X    register int cnt = 0, new = 0, unread = 0, deleted = 0;
  1283. X
  1284. X    for ( ; cnt < msg_cnt; cnt++) {
  1285. X    if (ison(msg[cnt].m_flags, UNREAD))
  1286. X        unread++;
  1287. X    if (ison(msg[cnt].m_flags, DELETE))
  1288. X        deleted++;
  1289. X    if (isoff(msg[cnt].m_flags, OLD))
  1290. X        new++;
  1291. X    }
  1292. X    if (as_prompt) {
  1293. X    register char *p, *b = buf;
  1294. X    for (p = prompt; *p; p++)
  1295. X        if (*p == '\\')
  1296. X        switch (*++p) {
  1297. X            case 'n': case 'r': *b++ = '\n';
  1298. X            when 't': *b++ = '\t';
  1299. X            otherwise: *b++ = *p;
  1300. X        }
  1301. X        else if (*p == '%')
  1302. X        switch (*++p) {
  1303. X            case 'm':
  1304. X            b += strlen(sprintf(b,"%d",(msg_cnt)? current_msg+1:0));
  1305. X            when 't':
  1306. X            b += strlen(sprintf(b, "%d", msg_cnt));
  1307. X            when 'd':
  1308. X            b += strlen(sprintf(b, "%d", deleted));
  1309. X            when 'u':
  1310. X            b += strlen(sprintf(b, "%d", unread));
  1311. X            when 'n':
  1312. X            b += strlen(sprintf(b, "%d", new));
  1313. X            when 'f':
  1314. X            {
  1315. X            char *tail = rindex(mailfile, '/'); 
  1316. X            if (tail && tail[1])
  1317. X                b += Strcpy(b, tail+1);
  1318. X            else
  1319. X                /* Fall through */
  1320. X            case 'F':
  1321. X            b += Strcpy(b, mailfile);
  1322. X            if (ison(glob_flags, READ_ONLY))
  1323. X                b += Strcpy(b, " [read-only]");
  1324. X            }
  1325. X            when 'T': case 'D': case 'Y': case 'y':
  1326. X            case 'M': case 'N': case 'W':
  1327. X            b += Strcpy(b, Time(p, (long)0));
  1328. X            otherwise: *b++ = *p;
  1329. X        }
  1330. X        else if (*p == '!')
  1331. X        b += strlen(sprintf(b, "%d", hist_no+1));
  1332. X        else
  1333. X        *b++ = *p;
  1334. X    *b = 0;
  1335. X    print("%s", buf); /* use %s in case "buf" has any %'s in it */
  1336. X    return;
  1337. X    }
  1338. X    (void) sprintf(buf,"\"%s\"%s: %d message%s, %d new, %d unread",
  1339. X    mailfile, ison(glob_flags, READ_ONLY)? " [read only]" : "",
  1340. X    msg_cnt, (msg_cnt != 1)? "s": NO_STRING, new, unread);
  1341. X    if (istool || iscurses)
  1342. X    (void) sprintf(buf+strlen(buf), ", %d deleted", deleted);
  1343. X#ifdef SUNTOOL
  1344. X    if (istool) {
  1345. X    static char ic_text[4];
  1346. X    extern struct pixrect mail_icon_image1, mail_icon_image2;
  1347. X    (void) sprintf(ic_text, "%3d", msg_cnt);
  1348. X    tool_set_attributes(tool,
  1349. X        WIN_LABEL, buf,
  1350. X        WIN_ICON_LABEL, ic_text,
  1351. X        WIN_ICON_IMAGE, ison(glob_flags, NEW_MAIL)?
  1352. X        &mail_icon_image2 : &mail_icon_image1,
  1353. X        0);
  1354. X    } else
  1355. X#endif /* SUNTOOL */
  1356. X#ifdef CURSES
  1357. X    if (iscurses) {
  1358. X        move (0, 0);
  1359. X        printw("%-3d %-.*s",
  1360. X        ((msg_cnt)? current_msg+1 : 0), COLS-5, buf), clrtoeol();
  1361. X    } else
  1362. X#endif /* CURSES */
  1363. X        puts(buf);
  1364. X    return;
  1365. X}
  1366. X
  1367. X/*
  1368. X *  For uucp mailers that use >From lines with "remote from <path>":
  1369. X * (where "path" is a hostname or pathnames)
  1370. X *
  1371. X *  a. Set the return_path to the empty string.
  1372. X *  b. For each From_ or >From_ line:
  1373. X *  c. Save the username (second token).
  1374. X *  d. Save the date (3-7 tokens).
  1375. X *  e. If it has a "remote from" then append the remote host
  1376. X *    (last token) followed by a "!" to the return_path.
  1377. X *  f. If the saved username has a '@' but no '!' then convert it
  1378. X *    to UUCP path form.
  1379. X *  g. Append the saved username to return_path.
  1380. X */
  1381. Xparse_from(fp, path)
  1382. XFILE *fp;
  1383. Xchar path[];
  1384. X{
  1385. X    char user[256], buf[256]; /* max size for each line in a mail file */
  1386. X    register char *p;
  1387. X    long save_offset = ftell(fp);
  1388. X
  1389. X    path[0] = '\0';
  1390. X    while (fgets(buf, sizeof buf, fp)) {
  1391. X    if (strncmp(buf, ">From ", 6))
  1392. X        break;
  1393. X    p = buf + 6;
  1394. X
  1395. X    (void) sscanf(p, "%s", user);
  1396. X
  1397. X    while (p = index(p+1, 'r')) {
  1398. X        if (!strncmp(p, "remote from ", 12)) {
  1399. X        char *p2 = path+strlen(path);
  1400. X        skipspaces(12);
  1401. X        sscanf(p, "%s", p2); /* add the new machine to current path */
  1402. X        (void) strcat(p2, "!");
  1403. X        break;
  1404. X        }
  1405. X    }
  1406. X
  1407. X    if (p)
  1408. X        (void) bang_form(path + strlen(path), user);
  1409. X    save_offset = ftell(fp);
  1410. X    }
  1411. X    fseek(fp, save_offset, L_SET);
  1412. X}
  1413. X
  1414. X/*
  1415. X * Scan a file and select messages from it and append them to the current folder
  1416. X *
  1417. X * If "append" is 1, start where we left off (held in msg[cnt].m_offset)
  1418. X * and scan for messages.  Append all messages found until EOF.
  1419. X *
  1420. X * If "append" is 2, we're merging in a new file, so start at the end of
  1421. X * the present folder and append all messages found until EOF.
  1422. X *
  1423. X * If "append" is 0, then the message separator must exist once and
  1424. X * only once.  All extra occurrences of the separator is preceded by a '>'.
  1425. X * The list argument will be the message number to replace in the current
  1426. X * folder with the message read in from other filename.
  1427. X */
  1428. Xload_folder(file, append, list)
  1429. Xchar *file, *list;
  1430. Xint append;
  1431. X{
  1432. X    char    buf[BUFSIZ];
  1433. X    int        lines = 0, msg_found = 0, had_error = 1;
  1434. X    int        get_status = 1, cnt;
  1435. X    long    bytes, ftell();
  1436. X    struct msg  old;
  1437. X    char    wkday[4], month[4];
  1438. X    int        day, year, mins, hour;
  1439. X    FILE       *fp;
  1440. X#ifdef MMDF
  1441. X    int        begin_sep = 0; /* track beginning vs ending separators */
  1442. X#endif /* MMDF */
  1443. X
  1444. X    if (!(fp = fopen(file, "r"))) {
  1445. X    error("Unable to open %s", file);
  1446. X    return -1;
  1447. X    }
  1448. X
  1449. X    if (append) {
  1450. X    cnt = msg_cnt;
  1451. X    (void) fseek(fp, append == 1 ? msg[cnt].m_offset : 0L, L_SET);
  1452. X    } else {
  1453. X    cnt = (int)list;
  1454. X    old = msg[cnt];
  1455. X    }
  1456. X
  1457. X    if (isoff(glob_flags, READ_ONLY)) {
  1458. X    if (tmpf)
  1459. X        (void) fclose(tmpf);
  1460. X    if (!(tmpf = mask_fopen(tempfile, "a"))) {
  1461. X        error("Unable to open %s for appending", tempfile);
  1462. X        (void) fclose(fp);
  1463. X        return -1;
  1464. X    }
  1465. X    (void) fseek(tmpf, 0L, 2); /* assure we're at the end of the file */
  1466. X    } else if (append == 2) {
  1467. X    /* you can't merge in a folder to a read-only folder */
  1468. X    (void) fclose(fp);
  1469. X    return -1;
  1470. X    }
  1471. X
  1472. X#ifdef MMDF
  1473. X    if (!append) {
  1474. X    strcpy(buf, MSG_SEPARATOR);
  1475. X    goto do_headers;
  1476. X    }
  1477. X#endif /* MMDF */
  1478. X    while (fgets(buf, sizeof (buf), fp)) {
  1479. X#ifndef MSG_SEPARATOR
  1480. X    if (!strncmp(buf, "From ", 5) &&
  1481. X        /* From uucp Wed Jan 11 20:40:00 1989 */
  1482. X        (sscanf(buf+5, "%*s %3s %3s %d %d:%d:%*d %d",
  1483. X        wkday, month, &day, &hour, &mins, &year) == 6 ||
  1484. X        /* From uucp Wed Jan 11 20:40:00 PST 1989 */
  1485. X        sscanf(buf+5, "%*s %3s %3s %d %d:%d:%*d %*s %d",
  1486. X            wkday, month, &day, &hour, &mins, &year) == 6 ||
  1487. X        /* From uucp Wed Jan 11 20:40 PST 1989 */
  1488. X        sscanf(buf+5, "%*s %3s %3s %d %d:%d %*s %d",
  1489. X            wkday, month, &day, &hour, &mins, &year) == 6))
  1490. X#else /* MSG_SEPARATOR */
  1491. X    if (!strncmp(buf, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
  1492. X#endif /* MSG_SEPARATOR */
  1493. X    {
  1494. X#ifdef MMDF
  1495. X        if (!append)
  1496. X        fputc('>', tmpf);
  1497. X        else if (begin_sep = !begin_sep)
  1498. Xdo_headers:
  1499. X#else /* MMDF */
  1500. X        if (!append && msg_found)
  1501. X        fputc('>', tmpf);
  1502. X        else
  1503. X#endif /* MMDF */
  1504. X        {
  1505. X        msg_found++;
  1506. X        had_error = 0;
  1507. X        if (append && cnt == MAXMSGS-2) {
  1508. X            wprint("WARNING: exceeded %d messages.\n", MAXMSGS);
  1509. X            wprint("Not all messages have been loaded.\n");
  1510. X            had_error++;
  1511. X            break;
  1512. X        }
  1513. X        if (ison(glob_flags, READ_ONLY))
  1514. X            bytes = ftell(fp) - strlen(buf);
  1515. X        else {
  1516. X            char path[256];
  1517. X            parse_from(fp, path);
  1518. X            if (path[0])
  1519. X            (void) sprintf(buf, "From %s %s %s %d %d:%d:00 %d\n",
  1520. X                path, wkday, month, day, hour, mins, year);
  1521. X            bytes = ftell(tmpf);
  1522. X        }
  1523. X        /* finish up message structure from previous message.
  1524. X         * if this is incorporating new mail, check "lines" to
  1525. X         * see if previous message has already been set!
  1526. X         */
  1527. X        if (cnt && lines) {
  1528. X            msg[cnt-1].m_size = bytes - msg[cnt-1].m_offset;
  1529. X            msg[cnt-1].m_lines = lines;
  1530. X        }
  1531. X        if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
  1532. X            error(tempfile);
  1533. X            had_error++;
  1534. X            break;
  1535. X        }
  1536. X        msg[cnt].m_offset = bytes;
  1537. X        msg[cnt].m_flags = 0L;
  1538. X        lines = 0;
  1539. X#ifndef MSG_SEPARATOR
  1540. X        if (year > 1900)
  1541. X            year -= 1900;
  1542. X        (void) sprintf(buf, "%02d%02d%02d%02d%02d%.3s",
  1543. X            year, month_to_n(month), day, hour, mins, wkday);
  1544. X        strdup(msg[cnt].m_date_recv, buf);
  1545. X#endif /* MSG_SEPARATOR */
  1546. X        turnon(msg[cnt].m_flags, UNREAD); /* initialize */
  1547. X
  1548. X        /* we've read the "From " line(s), now read the rest of
  1549. X         * the message headers till we get to a blank line.
  1550. X         */
  1551. X        while (fgets(buf, sizeof (buf), fp) && (*buf != '\n')) {
  1552. X            register char *p = buf;
  1553. X            if (!strncmp(buf, "Date:", 5))
  1554. X            strdup(msg[cnt].m_date_sent, parse_date(p+5));
  1555. X            if (get_status &&
  1556. X            !(get_status = strncmp(p, "Status:", 7))) {
  1557. X            /* new mail should not have a Status: field! */
  1558. X            turnon(msg[cnt].m_flags, OLD);
  1559. X            for (p += 8 ; *p != '\n'; p++)
  1560. X                switch(*p) {
  1561. X                case 'R': turnoff(msg[cnt].m_flags, UNREAD);
  1562. X                when 'P': turnon(msg[cnt].m_flags, UNREAD);
  1563. X                when 'S': turnon(msg[cnt].m_flags, SAVED);
  1564. X                when 'r': turnon(msg[cnt].m_flags, REPLIED);
  1565. X                when 'O': ; /* do nothing */
  1566. X                otherwise :
  1567. X                    if (ison(glob_flags, WARNING))
  1568. X                    print("unknown msg status flag: %c",*p);
  1569. X                }
  1570. X            }
  1571. X            if (isoff(glob_flags,READ_ONLY) && fputs(buf, tmpf) == -1) {
  1572. X            error(tempfile);
  1573. X            had_error++;
  1574. X            break;
  1575. X            }
  1576. X            lines++;
  1577. X        }
  1578. X        if (!msg[cnt].m_date_sent || !*msg[cnt].m_date_sent)
  1579. X            if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv) {
  1580. X            wprint("Message %d has *no* date!?\n", cnt+1);
  1581. X            msg[cnt].m_date_sent = msg[cnt].m_date_recv =
  1582. X                "0000000000XXX";
  1583. X            } else
  1584. X            strdup(msg[cnt].m_date_sent, msg[cnt].m_date_recv);
  1585. X        else if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv)
  1586. X            strdup(msg[cnt].m_date_recv, msg[cnt].m_date_sent);
  1587. X        if (had_error)
  1588. X            break;
  1589. X        if (append && list)
  1590. X            set_msg_bit(list, cnt);
  1591. X        if (append)
  1592. X            cnt = ++msg_cnt;
  1593. X        get_status = 1;
  1594. X        }
  1595. X    }
  1596. X    if (msg_found) {
  1597. X        lines++;
  1598. X        if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
  1599. X        error(tempfile);
  1600. X        had_error++;
  1601. X        break;
  1602. X        }
  1603. X    }
  1604. X    }
  1605. X    if (msg_found && append != 1)
  1606. X    turnon(glob_flags, DO_UPDATE);
  1607. X#ifdef MMDF
  1608. X    if (!append)
  1609. X    fputs(END_MSG_SEP, tmpf);
  1610. X#endif /* MMDF */
  1611. X    if (had_error) {
  1612. X    if (!append)
  1613. X        msg[cnt] = old;
  1614. X    if (!msg_found && !append)
  1615. X        print("File not left in correct message format.\n");
  1616. X    } else {
  1617. X    if (append)
  1618. X        cnt--;
  1619. X    if (isoff(glob_flags, READ_ONLY))
  1620. X        msg[cnt].m_size = ftell(tmpf) - msg[cnt].m_offset;
  1621. X    else
  1622. X        msg[cnt].m_size = ftell(fp) - msg[cnt].m_offset;
  1623. X    msg[cnt].m_lines = lines;
  1624. X    /* remember where we were to seek to for when we append new mail */ 
  1625. X    if (append)
  1626. X        cnt++;
  1627. X    }
  1628. X    if (append)
  1629. X    msg[cnt].m_offset = ftell(fp);
  1630. X    fclose(fp);
  1631. X    if (isoff(glob_flags, READ_ONLY)) {
  1632. X    fclose(tmpf);
  1633. X    if (!(tmpf = fopen(tempfile, "r"))) {
  1634. X        error("Unable to open %s for reading", tempfile);
  1635. X        return -1;
  1636. X    }
  1637. X    }
  1638. X    return !had_error;
  1639. X}
  1640. END_OF_FILE
  1641. if test 24063 -ne `wc -c <'msgs.c'`; then
  1642.     echo shar: \"'msgs.c'\" unpacked with wrong size!
  1643. fi
  1644. # end of 'msgs.c'
  1645. fi
  1646. echo shar: End of archive 11 \(of 19\).
  1647. cp /dev/null ark11isdone
  1648. MISSING=""
  1649. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1650.     if test ! -f ark${I}isdone ; then
  1651.     MISSING="${MISSING} ${I}"
  1652.     fi
  1653. done
  1654. if test "${MISSING}" = "" ; then
  1655.     echo You have unpacked all 19 archives.
  1656.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1657. else
  1658.     echo You still need to unpack the following archives:
  1659.     echo "        " ${MISSING}
  1660. fi
  1661. ##  End of shell archive.
  1662. exit 0
  1663.